#include "Timer.h"
#include "Building.h"

/**
 * Implementation of the Building application.  
 * 
 * @author Mina Jung 
 * @date   May 31 2010
 */

module BuildingC {
  uses {
    interface Leds;
    interface Boot;
    interface Interrupt;

    interface Receive;
    interface AMSend;
    interface Timer<TMilli> as Timer0;
    interface Timer<TMilli> as Timer1;
    interface Timer<TMilli> as Timer2;
    interface Packet;
    interface Read<uint16_t>;
    interface SplitControl as RadioControl;
    interface TaskUrgent as CO2Task;
    interface TaskUrgent as TempTask;
    interface TaskUrgent as LightTask;
    interface TaskUrgent as MotionTask;
    interface TaskUrgent as CameraTask;
  }
}
implementation {

  message_t packet;

  uint8_t timerFreq;
  uint8_t appID;             /* SENSE */
  uint8_t booted = 0;        
  uint16_t counter = 0;      /* COUNT */

  bool locked = FALSE;
   
  event void Boot.booted(uint8_t app, uint8_t freq) {
    appID = app;
    timerFreq = freq;

dbg("Building", "Application ID:% hu Booted\n", appID);
    call RadioControl.start();
  }


  event void CO2Task.runTask() // timer polling
  {

    if(!booted)
      return;

dbg("Building", "TASK Abnormal CO2 Level(%hu)\n", appID);
    if(locked) {
      return;
    }
    else {
      radio_multi_msg_t* rmm = (radio_multi_msg_t*)call Packet.getPayload(&packet, sizeof(radio_multi_msg_t));
      if(rmm == NULL) {
        return;
      }
            
      rmm->type = appID;
      rmm->data = 3;

      if(call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_multi_msg_t)) == SUCCESS) {
dbg("Building", "CO2 TASK Message sent\n");
        locked = TRUE;
      }
    }

  }

  event void TempTask.runTask() // timer polling
  {

    if(!booted)
      return;
dbg("Building", "Abnormal Temperature(%hu)\n", appID);
    if(locked) {
      return;
    }
    else {
      radio_multi_msg_t* rmm = (radio_multi_msg_t*)call Packet.getPayload(&packet, sizeof(radio_multi_msg_t));
      if(rmm == NULL) {
        return;
      }
            
      rmm->type = appID;
      rmm->data = 4;

      if(call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_multi_msg_t)) == SUCCESS) {
dbg("Building", "TEMP TASK Message sent\n");
        locked = TRUE;
      }
    }

  }

  event void LightTask.runTask() // timer polling
  {
    if(!booted)
      return;

dbg("Building", "Too Dark(%hu)\n", appID);
    if(locked) {
      return;
    }
    else {
      radio_multi_msg_t* rmm = (radio_multi_msg_t*)call Packet.getPayload(&packet, sizeof(radio_multi_msg_t));
      if(rmm == NULL) {
        return;
      }
            
      rmm->type = appID;
      rmm->data = 5;

      if(call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_multi_msg_t)) == SUCCESS) {
dbg("Building", "LIGHT TASK Message sent\n");
        locked = TRUE;
      }
    }

  }

  event void MotionTask.runTask() // by interrupt
  {
    if(!booted)
      return;

dbg("Building", "Detect an individual movement\n");
    if(locked) {
      return;
    }
    else {
      radio_multi_msg_t* rmm = (radio_multi_msg_t*)call Packet.getPayload(&packet, sizeof(radio_multi_msg_t));
      if(rmm == NULL) {
        return;
      }
            
      rmm->type = appID;
      rmm->data = 1;

      if(call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_multi_msg_t)) == SUCCESS) {
dbg("Building", "MOTION TASK Message sent\n");
        locked = TRUE;
      }
    }

  }

  event void CameraTask.runTask() // by interrupt
  {
    if(!booted)
      return;

dbg("Building", "Detect a moving object\n");
    if(locked) {
      return;
    }
    else {
      radio_multi_msg_t* rmm = (radio_multi_msg_t*)call Packet.getPayload(&packet, sizeof(radio_multi_msg_t));
      if(rmm == NULL) {
        return;
      }
            
      rmm->type = appID;
      rmm->data = 2;

      if(call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_multi_msg_t)) == SUCCESS) {
dbg("Building", "CAMERA TASK Message sent\n");
        locked = TRUE;
      }
    }

  }

  event void RadioControl.startDone(error_t err) {
    if (err == SUCCESS) {
dbg("Building", "RADIO Start\n");
      switch(appID)
      {
        case 1: /* Motion Detector */
               break;
        case 2: /* Camera Sensor */
               break;
      
        case 3: /* General Sensor */
dbg("Building", "Start Timers\n");
               call Timer0.startPeriodic(700);
               call Timer1.startPeriodic(1100);
               call Timer2.startPeriodic(3100);
               break;
      }

      booted = 1;
    }
    else {
      call RadioControl.start();
    }

  }

  event void RadioControl.stopDone(error_t err) {}
  

  event void Timer0.fired() {
    // read CO2
dbg("Building", "CO2 CHECK\n");
    call Read.read(3);
  }

  event void Timer1.fired() {
    // read Temperature
dbg("Building", "TEMP CHECK\n");
    call Read.read(4);
  }

  event void Timer2.fired() {
    // read Light Level
dbg("Building", "LIGHT CHECK\n");
    call Read.read(5);
  }

  /* Sensing Done */
  event void Read.readDone(error_t result, uint16_t type, uint16_t data) {

dbg("Building", "Sensing is DONE\n");
    switch(type)
    {
      case 3:
dbg("Building", "CO2 TASK POST\n");
             if(data > 0)
             call CO2Task.postTask(5, 5, 3);
             break;

      case 4:
dbg("Building", "TEMP TASK POST\n");
             if(data > 0)
             call TempTask.postTask(2, 300, 3);
             break;

      case 5:
dbg("Building", "LIGHT TASK POST\n");
             if(data > 0)
             call LightTask.postTask(1, 500, 3);
             break;
    }
  }


  event void Interrupt.fired(uint8_t type){
dbg("Building", "Interrupt OCCUR!!\n");
    if(type == 1) {
dbg("Building", "MOTION TASK POST\n");
      call MotionTask.postTask(4, 10, 1);
    }
    else if(type == 2) {
dbg("Building", "CAMERA TASK POST\n");
      call CameraTask.postTask(3, 100, 2);
    }
  }

  event message_t* Receive.receive(message_t* bufPtr, 
				   void* payload, uint8_t len) {

dbg("Building", "Receive a Message\n");

    if (len != sizeof(radio_multi_msg_t)) {return bufPtr;}
    else {
      radio_multi_msg_t* rmm = (radio_multi_msg_t*)payload;
      uint16_t val = rmm->data;
      uint16_t type = rmm->type;

      switch(type)
      {
        case 1: /* Motion */
               call Leds.led0Toggle();
               call Leds.led1Toggle();
               call Leds.led2Toggle();

               break;
        case 2: /* Camera */
               call Leds.led0Toggle();
               call Leds.led1Toggle();
               call Leds.led2Toggle();

               break;
        case 3: /* Sense */
               call Leds.led0Toggle();
               call Leds.led1Toggle();
               call Leds.led2Toggle();
               break;
      }

      return bufPtr;
    }
  }

  event void AMSend.sendDone(message_t* bufPtr, error_t error) {
    if (&packet == bufPtr) {
      locked = FALSE;
    }
  }

}
